/*
 * Copyright 2020 zytech
 * All rights reserved.
 *
 * author :guyadong
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef _EMBEDDED_RPC__DUAL_SERIAL_TRANSPORT_H_
#define _EMBEDDED_RPC__DUAL_SERIAL_TRANSPORT_H_

#include "erpc_framed_transport.h"
#include "erpc_threading.h"
#include <string>
#include <termios.h>

/*!
 * @addtogroup serial_transport
 * @{
 * @file
 */

////////////////////////////////////////////////////////////////////////////////
// Classes
////////////////////////////////////////////////////////////////////////////////

namespace erpc {
/*!
 * @brief 双向串行通讯传输层实现
 *        bidirectional serial transport layer for host PC
 *
 * @ingroup serial_transport
 */
class DualSerialTransport : public FramedTransport
{
public:
    /*!
     * @brief Constructor.
     *
     * @param[in] portName Port name.
     * @param[in] baudRate Baudrate.
     * @param[in] baudRate Baudrate.
     * @param[in] isServer True when this transport is used for server side application.
     */
    DualSerialTransport(const char *portName, speed_t baudRate, bool isServer);

    /*!
     * @brief Destructor.
     */
    virtual ~DualSerialTransport(void);
    /*!
     * @brief This function set host and port of this transport layer.
     *
     * @param[in] selfSem Specify self receive semaphore.
     * @param[in] switchSem Specify switch semaphore.
     * @param[in] sendLock Specify send lock.
     * @param[in] extSem Specify extensive client receive semaphore(only for server).
     * @return Status of function.
     */
    erpc_status_t configure(Semaphore *selfSem,Semaphore *switchSem,Mutex *sendLock,Semaphore *extSem);
    /*!
     * @brief Initialize Serial peripheral.
     *
     * @param[in] vtime Read timeout.
     * @param[in] vmin Read timeout min.
     * @param[inout] serialHandle pointer to Serial handle id.
     *               for server transport, initialize serial port,and store the Serial handle id to it,
     *               for client transport, store the input Serial handle id to m_serialHandle ,
     * @return Status of function.
     */
    erpc_status_t init(uint8_t vtime, uint8_t vmin, int *serialHandle);
    /*!
     * @brief This function will start switcher thread on server side
     *
     * @return Status of init function.
     * @retval #kErpcStatus_Success always
     */
    erpc_status_t open(void);
    /*!
     * @brief This function will stop switcher thread on server side,and close serial port
     *
     * @return Status of function.
     * @retval #kErpcStatus_Success always
     */
    erpc_status_t close(void);
protected:
    /*!
     * @brief Write data to Serial peripheral.
     *
     * @param[in] data Buffer to send.
     * @param[in] size Size of data to send.
     *
     * @retval kErpcStatus_ReceiveFailed Serial failed to receive data.
     * @retval kErpcStatus_Success Successfully received all data.
     */
    virtual erpc_status_t underlyingSend(const uint8_t *data, uint32_t size);

    /*!
     * @brief Receive data from Serial peripheral.
     *
     * @param[inout] data Preallocated buffer for receiving data.
     * @param[in] size Size of data to read.
     *
     * @retval kErpcStatus_ReceiveFailed Serial failed to receive data.
     * @retval kErpcStatus_Success Successfully received all data.
     */
    virtual erpc_status_t underlyingReceive(uint8_t *data, uint32_t size);
    /*!
     * @brief Server thread function.
     */
    void serverThread(void);

    /*!
     * @brief Thread entry point.
     *
     * Control is passed to the serverThread() method of the TCPTransport instance pointed to
     * by the @c arg parameter.
     *
     * @param arg Thread argument. The pointer to the TCPTransport instance is passed through
     *  this argument.
     */
    static void serverThreadStub(void *arg);

private:
    int m_serialHandle;     /*!< Serial handle id. */
    const char *m_portName; /*!< Port name. */
    speed_t m_baudRate;     /*!< Bauderate. */
    bool m_isServer;        /*!< If true then server is using transport, else client. */
    Thread m_serverThread;  /*!< Pointer to server thread. */
    bool m_runServer;       /*!< Thread is executed while this is true. */
    Semaphore *m_selfSem;   /*!< self receive semaphore. */
    Semaphore *m_extSem;    /*!< ext client receive semaphore. */
    Semaphore *m_switchSem; /*!< switch semaphore. */
    Mutex *m_sendLock;      /*!< lock for send. */
    const uint32_t m_segType; /*!< data segment first char const */
};

} // namespace erpc

/*! @} */

#endif // _EMBEDDED_RPC__DUAL_SERIAL_TRANSPORT_H_
